package com.uva.dbcs.gestionDeReservaAlquiler.despliegue.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Stateless;

import com.uva.dbcs.gestionDeReservaAlquiler.despliegue.GestorAlquilerReservaLocal;
import com.uva.dbcs.gestionDeReservaAlquiler.dominio.Alquiler;
import com.uva.dbcs.gestionDeReservaAlquiler.dominio.Entrega;
import com.uva.dbcs.gestionDeReservaAlquiler.dominio.Reserva;
import com.uva.dbcs.gestionDeReservaAlquiler.persistencia.AlquilerDAO;
import com.uva.dbcs.gestionDeReservaAlquiler.persistencia.EntregaDAO;
import com.uva.dbcs.gestionDeReservaAlquiler.persistencia.ReservaDAO;
import com.uva.dbcs.gestionDeVehiculos.despliegue.GestorDeVehiculosLocal;
import com.uva.dbcs.gestionDeVehiculos.dominio.Modelo;
import com.uva.dbcs.gestionDeVehiculos.dominio.Vehiculo;

/**
 * Session Bean implementation class GestorAlquilerReserva
 */
@Stateless
public class GestorAlquilerReserva implements GestorAlquilerReservaLocal {

	// Dependencias con otros componentes.
	@EJB
	GestorDeVehiculosLocal gestorDeVehiculos;
	
	// Daos
	@EJB
	AlquilerDAO alquilerDAO;

	@EJB
	EntregaDAO entregaDAO;

	@EJB
	ReservaDAO reservaDAO;

	public GestorAlquilerReserva() {
	}

	@Override
	public List<Alquiler> getAlquileres() {
		return alquilerDAO.findAll();
	}

	@Override
	public List<Entrega> getEntregas() {
		return entregaDAO.findAll();
	}

	@Override
	public List<Reserva> getReservas() {
		return reservaDAO.findAll();
	}

	@Override
	public Reserva getReservaByID(int idReserva) {
		return reservaDAO.find(idReserva);
	}

	@Override
	public Entrega getEntregaByID(int idEntrega) {
		return entregaDAO.find(idEntrega);
	}

	@Override
	public Alquiler getAlquilerByID(int idAlquiler) {
		return alquilerDAO.find(idAlquiler);
	}

	@Override
	public void crearReserva(Date fechaReserva, Date fechaInicioAlquiler,
			Date fechaFinAlquiler, int idCliente, int idVehiculo) {

		Reserva r = new Reserva(false, fechaFinAlquiler, fechaInicioAlquiler,
				fechaReserva, idCliente, idVehiculo);

		reservaDAO.create(r);
	}

	@Override
	public void crearAlquiler(Date fechaInicio, Date fechaFin, int idCliente,
			int idVehiculo, int kilometrajeSalida, double precio) {

		Alquiler a = new Alquiler(fechaFin, fechaInicio, idCliente, idVehiculo,
				kilometrajeSalida, precio);

		alquilerDAO.create(a);
	}

	@Override
	public void crearEntrega(int idAlquiler, Date fechaEntrega, int idEmpleado,
			int KilometrajeEntrega) {

		Entrega e = new Entrega(idAlquiler, fechaEntrega, idEmpleado,
				KilometrajeEntrega);

		entregaDAO.create(e);
	}

	@Override
	public void actualizarEstadoReserva(int idReserva) {

		Reserva r = reservaDAO.find(idReserva);
		r.setEjecutada(true);
        
	}

	@Override
	public List<Vehiculo> buscarVehiculosDisponibles(int idModelo,
			Date fechaInicio, Date fechaFin) {
		
		Modelo m = gestorDeVehiculos.getModeloById(idModelo);
		
		// obtener vehiculos del modelo indicado
		
		List<Vehiculo> vehiculos_inicial;
		List<Vehiculo> vehiculos_filtrados;
		
		if (m!=null){
		
		vehiculos_inicial = m.getVehiculos();//OJO! se puede hacer por que la relacion es eager.
		
		} else{
		vehiculos_inicial = gestorDeVehiculos.getVehiculos();
		}
		// comprobar si estos vehiculos están alquilados
		// o reservador para las fechas introducidas.
		

		vehiculos_filtrados =filtrarVehiculosDisponibles(vehiculos_inicial, fechaInicio, fechaFin);
		
		return vehiculos_filtrados;
	}



	@Override
	public List<Vehiculo> buscarVehiculosDisponibles(int costeMaximo,
			int costeMinimo, Date fechaInicio, Date fechaFin, boolean gps,
			int idFabricante, int puertas) {
		
		// obtener vehculos del de las características indicadas
		
		List<Vehiculo> vehiculos_inicial;
		List<Vehiculo> vehiculos_filtrados;
		
		vehiculos_inicial = gestorDeVehiculos.getVehiculos(costeMaximo,
				costeMinimo,gps,
				idFabricante, puertas);
		
		// comprobar si estos vehiculos están alquilados
		// o reservador para las fechas introducidas.
		

		vehiculos_filtrados =filtrarVehiculosDisponibles(vehiculos_inicial, fechaInicio, fechaFin);
		
		return vehiculos_filtrados;
	}
	
	/**
	 * Filtra los vehículos pasados con los realmente disponibles, basandose
	 * en las reservas y alquileres hechos.
	 * @param vehiculos_inicial
	 * @param fechaInicio
	 * @param fechaFin
	 * @return
	 */
	private List<Vehiculo> filtrarVehiculosDisponibles(
			List<Vehiculo> vehiculos_inicial, Date fechaInicio, Date fechaFin) {
		
		List<Integer> listaIdsVehiculos = new ArrayList<Integer>();
		Collections.sort(listaIdsVehiculos); 
		List<Vehiculo> vehiculos_filtrados = new ArrayList<Vehiculo>();
		
		
		for (int i = 0; i < vehiculos_inicial.size(); i++) {
			
			listaIdsVehiculos.add( vehiculos_inicial.get(i).getIdvehiculo());
		}
		
		List<Reserva> reservas = reservaDAO.findReservas(listaIdsVehiculos,fechaInicio,fechaFin);
		
		// filtramos los vehiculos que estén reservados
		
		for (int i = 0; i < reservas.size(); i++) {
			
			listaIdsVehiculos.remove(Collections.binarySearch(listaIdsVehiculos, reservas.get(i).getIdVehiculo()));
		}
		
		
		// obtenemos los alquileres
		
		List<Alquiler> alquileres = alquilerDAO.findAlquileres(listaIdsVehiculos,fechaInicio,fechaFin);
		
		
		// de los vehiculos restantes de las reservas restamos los que
		// estén alquilados.
		
		for (int i = 0; i < alquileres.size(); i++) {
			
			listaIdsVehiculos.remove(Collections.binarySearch(listaIdsVehiculos, alquileres.get(i).getIdVehiculo()));
		}
		
		// devolver los vehículos restantes
		for (int i = 0; i < vehiculos_inicial.size(); i++) {
			
			int id;
			id = Collections.binarySearch(listaIdsVehiculos, vehiculos_inicial.get(i).getIdvehiculo());
			
			if (id>=0){
				vehiculos_filtrados.add(vehiculos_inicial.get(i));
			}
		}
		
		return vehiculos_filtrados;
		
	}

}
